using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Universe.Farm.Service.Mesages;

namespace Universe.Farm.Service
{
    class DeliveryAgent: FarmAgent
    {
        private int _counter = 0;


        public DeliveryAgent(FarmState farmState) : base(farmState)
        {
        }

        public void Deliver(IMessage message)
        {
            byte[] bytes = MessageIO.Serialize(message);
            IBufferProtocol bp = base.TheFarmState.Config.ResolveRequired<IBufferProtocol>();
            bytes = bp.Encode(bytes);
            Debug.WriteLine(
                "Deliver " 
                + message.GetType().Name 
                + (message is AnnounceMessage ? " " + (message as AnnounceMessage).IdService : "")
                + " [" + bytes.Length + " bytes]");

            if (TheFarmState.CommunicationParameters.IsBroadcast)
            {
                Interlocked.Increment(ref _counter);
                ThreadPool.QueueUserWorkItem(
                    delegate
                    {
                        ApplyThreadName();
                        using (UdpClient udp = new UdpClient(0))
                        {
                            IPEndPoint ep = new IPEndPoint(IPAddress.Broadcast, TheFarmState.CommunicationParameters.Port);
                            udp.Send(bytes, bytes.Length, ep);
                        }
                        Interlocked.Decrement(ref _counter);
                    });
            }

            foreach (IPAddress address in TheFarmState.CommunicationParameters.PeerList)
            {
                Interlocked.Increment(ref _counter);
                ThreadPool.QueueUserWorkItem(
                    delegate
                    {
                        ApplyThreadName();
                        using (UdpClient udp = new UdpClient(0))
                        {
                            IPEndPoint ep = new IPEndPoint(address, TheFarmState.CommunicationParameters.Port);
                            udp.Send(bytes, bytes.Length, ep);
                        }
                        Interlocked.Decrement(ref _counter);
                    });
            }
        }

        public void Close()
        {
            while (true)
            {
                if (Interlocked.Add(ref _counter, 0) <= 0)
                    return;

                Thread.Sleep(100);
            }
        }

        static void ApplyThreadName()
        {
#if DEBUG
            try
            {
                Thread.CurrentThread.Name = "Server Farm Delivery";
            }
            catch
            {
            }
#endif
        }

    }

}
